home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’96
/
Venus
/
SimpleWindow.cc
< prev
next >
Wrap
Text File
|
1996-06-22
|
14KB
|
438 lines
/*
***********************************************************************
*
* Simple Window Class
* A generic simple window that can be dragged around the screen
* and closed by clicking a "go-away" button
* No other events are handled, redefine the event handler if necessary.
*
*
***********************************************************************
*/
#include "image.h"
#include "mymenv.h"
#include "window.h"
//#include <PictUtil.h>
/*
*----------------------------------------------------------------------
* Service functions
*/
// Getting a bounding rectangle of an image
ScreenRect::ScreenRect(const IMAGE& image)
{
left = top = 0;
right = image.q_ncols();
bottom = image.q_nrows();
}
#if 0
// Create a rectangle of given height/width
// positioned at the origin
ScreenRect::ScreenRect(const rowcol& heightwidth)
{
left = top = 0;
bottom = heightwidth.row();
right = heightwidth.col();
}
// Create a rectangle of given height/width
// positioned at a given point
ScreenRect::ScreenRect(const rowcol& origin, const rowcol& heightwidth)
{
top = origin.row();
left = origin.col();
bottom = top+heightwidth.row();
right = left+heightwidth.col();
}
#endif
// Shifting a rectangle by the same amount
// in X and Y
ScreenRect& ScreenRect::operator += (const int offset)
{
top += offset; bottom += offset; left += offset; right += offset;
return *this;
}
// Print what rectangle is this
void ScreenRect::print(const char * title) const
{
alert("Rectangle %s (%d,%d) - (%d,%d)",title,top,left,bottom,right);
}
#if 0
/*
*----------------------------------------------------------------------
* Primitive Window creators/destructors
*/
// This is a protected constructor. Normally
// objects XVTBasicWindow are created as a part
// of a derived class
XVTBasicWindow::XVTBasicWindow(void)
{
Not_canceled = FALSE;
this_window = NULL_WIN;
}
// Destroy the window if it hasn't been destroyed
// already
XVTBasicWindow::~XVTBasicWindow(void)
{
if( this_window != 0 )
close_window(this_window);
}
// Close the window
void XVTBasicWindow::cancel(void)
{
Not_canceled = FALSE;
if( this_window != 0 )
close_window(this_window);
}
/*
*----------------------------------------------------------------------
* Basic event dispatching/handling
*/
// A universal event handler: does almost nothing
// but watches creation and destruction of windows
// (to tell when there are no windows to watch)
// For any other tasks, it calls the handler of
// a particular window
int XVTBasicWindow::no_opened_windows = 0;
long XVTBasicWindow::universal_handler(WINDOW win, EVENT *ep)
{
XVTBasicWindow& the_window = *(XVTBasicWindow *)get_app_data(win);
if( ep->type == E_CREATE )
no_opened_windows++, the_window.this_window = win;
the_window.handler(*ep);
// XVT would destroy the window after this
// event
if( ep->type == E_DESTROY )
no_opened_windows--, the_window.this_window = 0;
return 0;
}
// Serve the windows until all get closed
void XVTBasicWindow::serve_to_death(void)
{
while( no_opened_windows>0 )
process_events();
}
// Event handler for a particular window
// Finally, a handler which really does smth
// specific
void XVTBasicWindow::handler(EVENT event)
{
switch(event.type)
{
case E_CREATE:
if( !initialize() )
cancel();
break;
}
}
/*
*----------------------------------------------------------------------
* Window creators
*
* Note, event processing may start *before* the create_* functions return!
* So, if initialize() or event handlers, etc rely on some data that are
* going to be initialized *after* create_* function, you're in trouble!
* It's better to call create() function the last thing in the constructor,
* or even not to call at all (call it separetely later) to allow derived
* classes initialize properly!
*
*/
#endif
/*
*----------------------------------------------------------------------
* Window creators
*/
// Create a color window of the specified size and title
// Note, the upper left corner of 'rect' must
// NOT be (0,0)!
ScreenWindow::ScreenWindow(ScreenRect rect, const char * title)
{
const int window_offset = 100; // Cannot be 0 or small!
this_window = NewCWindow(nil,rect += window_offset,(Pstr)title,
TRUE,noGrowDocProc,
(WindowPtr)(-1),TRUE,(long)this);
assert( this_window != 0 );
SetPort(this_window);
SelectWindow(this_window);
}
// Create a color window from a resource template
ScreenWindow::ScreenWindow(const short resource_id)
{
this_window = GetNewCWindow(resource_id,nil,(WindowPtr)(-1));
SetWRefCon(this_window,(long)this);
assert( this_window != 0 );
SetPort(this_window);
SelectWindow(this_window);
}
// I wouldn't've needed this is destructor had been really virtual. Right now,
// CW 6.0 accepts attribute virtual for the destructor, but doesn't override
// destructors as it does for virtual functions. Oh, well, another kludge
// Close the window and clean up the rubble
void ScreenWindow::destroy_it(void)
{
assert( this_window != 0 );
DisposeWindow(this_window);
this_window = 0;
}
/*
*----------------------------------------------------------------------
* Basic Even Handling
*/
// Top-level event dispatcher
// Returns FALSE when the window is to be destroyed
// and won't need any further events
Boolean ScreenWindow::handle_event(const EventRecord& the_event)
{
switch( the_event.what )
{
case mouseDown:
WindowPtr wp;
short windowPart = FindWindow(the_event.where, &wp);
if( !handle_mouse_down(the_event,wp,windowPart) )
return FALSE; // Window is to be closed (go-away buttin clicked)
break;
case updateEvt:
if( this_window == (WindowPtr)the_event.message )
update();
break;
case keyDown:
case autoKey:
if( !handle_key_down(the_event) )
return FALSE; // a "quit" key must've been pressed
break;
case activateEvt:
if( this_window == (WindowPtr)the_event.message )
if( the_event.modifiers & 0x01 )
SetPort(this_window);
}
return TRUE;
}
// Handle "mouse-down" events
// Returns FALSE if the user clicked within the
// go-away region of our window. Otherwise,
// returns TRUE
// Handles dragging if necessary and system clicks
Boolean ScreenWindow::handle_mouse_down
(const EventRecord& the_event, WindowPtr where_window, short window_part)
{
switch( window_part )
{
case inSysWindow:
SystemClick(&the_event, where_window);
break;
case inMenuBar:
break; // Don't handle it yet
case inContent:
break;
case inDrag:
if( this_window == where_window )
DragWindow(this_window,the_event.where,&qd.screenBits.bounds);
break;
case inGoAway:
return !TrackGoAway(where_window, the_event.where);
}
return TRUE;
}
// Handles key_down & auto_key events. Return FALSE
// if the window is to be closed down
Boolean ScreenWindow::handle_key_down(const EventRecord& the_event)
{
return FALSE; // Any key kills the application, sorry
}
// Handles null events, when nothing happens for some
// time. Return FALSE when it's time to die
Boolean ScreenWindow::handle_null_event(const long event_time)
{
return TRUE; // Keep going
}
// Private window parts
// Handle an update event - redraw the window
// A virtual function draw() is called to do
// the actual redrawing
void ScreenWindow::update(void)
{
SetNewGrafPtr((GrafPtr)this_window);
BeginUpdate(this_window);
draw();
EndUpdate(this_window);
}
// Make the entire window being redrawn
void ScreenWindow::refresh(void)
{
InvalRect(&this_window->portRect);
}
/*
*----------------------------------------------------------------------
* An off-screen pixel buffer for faster drawing
*/
// Allocate the buffer for offscreen
// drawing and load a CLUT (if clut_id != 0)
OffScreenBuffer::OffScreenBuffer(ScreenRect rect, const short clut_id)
: graf_world(nil)
{
CTabHandle clut_handle = nil;
if( clut_id != 0 )
{ // try to get a user CLUT with that resource id
clut_handle = GetCTable(clut_id);
assert( clut_handle != 0 );
}
do_well( NewGWorld(&graf_world,8,rect,clut_handle,nil,0) );
assert( graf_world != nil );
if( clut_handle != nil )
DisposCTable(clut_handle); // CLUT has been copied, and can be disposed of now
// Get hold of the offscreen pixmap
pixmap = GetGWorldPixMap(graf_world); // and make sure it looks like
assert( pixmap != nil && *pixmap != nil ); // we can use it
assert( (**pixmap).cmpCount == 1 ); // We have a color table index
assert( !PixMap32Bit(pixmap) );
_height = abs((**pixmap).bounds.top - (**pixmap).bounds.bottom);
_width = abs((**pixmap).bounds.right - (**pixmap).bounds.left);
_bytes_per_row = (**pixmap).rowBytes & 0x7fff;
assert( _height > 0 && _height < 10000 ); // Just to play safe
assert( _width > 0 && _width <= _bytes_per_row );
}
// Dispose of the offscreen buffer
OffScreenBuffer::~OffScreenBuffer(void)
{
assert( graf_world != nil );
DisposeGWorld(graf_world);
graf_world = nil;
#if 0
PaletteHandle window_palette = GetPalette(our_window());
if( window_palette != nil ) // dispose of our palette if was allocated
{
SetPalette(our_window(),nil,FALSE);
DisposePalette(window_palette);
}
#endif
pixmap = nil;
_height = _width = _bytes_per_row = 0;
}
#if 0
// Make sure that the colors of our off-screen
// buffer would be displayed properly (or close enough)
// on screen
void OffScreenBuffer::activate_palette(void)
{
CTabHandle window_ctab = (**pixmap).pmTable;
assert( window_ctab != nil && *window_ctab != nil );
PaletteHandle palette = NewPalette((**window_ctab).ctSize,window_ctab,pmTolerant+pmExplicit,0);
assert( palette != nil );
SetPalette(our_window(),palette,TRUE);
do_well( QDError() );
ActivatePalette(our_window());
do_well( QDError() );
}
#endif
// Actual drawing - moving the picture from the
// offscreen grafworld to the onscreen one, to the current port.
// Remember to set a device to that of the offscreen
// grafworld before CopyBits (in order to get grafworld's color table and
// inverse color table to be used): see IM, Palette Manager
// Also note, if a window we're going to draw on is partly/completely
// obscured, then the visRgn, the visible region of the on-screen window,
// is *not* a window rectangle. When we make the offscreen grafworld the
// current grafport for CopyBits, CopyBits has no way of knowing then that
// the true destination region may not be the whole where_rect at all. To make
// CopyBits aware of the fact that the onscreen window maybe abscured, we
// pass the visRgn of the onscreen window as a clipping region to CopyBits.
// In that case CopyBits performs clipping just as if the onscreen window
// where the current grafport.
// Note, to be really precise, we ought to pass CopyBits() an intersection of
// onscreen grafport's visRgn and clipRgn. Well, we take a shortcut here:
// normally clipRgn is set to be the whole screen. Moreover, visRgn is clipped
// already not only to the unobscured part of the window, but to the update
// region as well. So using visRgn only should suffice....
// Also make sure that the onscreen window has a palette roughly corresponding
// to the CLUT of the grafworld (otherwise colors would be screwed up)
// One can use a palette resource 0 to be used as a default palette for
// dialogs/windows within the task
// Note there is a different way to force color translation when drawing a picture
// (seems to work better in 68k universe). One needs to create a grafworld, and
// and draw on it within OpenPicture()...ClosePicture(). Then one can draw
// thus recorded picture on the current window. The colors seem to get translated
// correctly, and one doesn't need to worry about clipping, etc (as in the method
// way explained above). One can use this technique to force 24->8 color
// translation (with dithering) if the grafworld was created as 24-bit.
void OffScreenBuffer::draw(const Rect& where_rect, const Rect& from_rect)
{
// const BitMap * where_pixmap = &qd.thePort->portBits; // see below
CGrafPtr old_port;
GDHandle old_gdevice;
GetGWorld(&old_port,&old_gdevice);
const RgnHandle where_visible_region = old_port->visRgn;
SetGWorld((CGrafPtr)graf_world,nil);
// The following line is actually the same as
// the one commented at the very top. However,
// thePort stuff doesn't work under OpenDoc, but
// the following line does.
const BitMap * where_pixmap = &((GrafPtr)old_port)->portBits;
//!!!Set_NewGrafWorld((GWorldPtr)graf_world); // Doesn't work: CW disposes of the object too early
assert( LockPixels(pixmap) );
CopyBits((const BitMap *)*pixmap, where_pixmap, &from_rect, &where_rect, /*ditherCopy*/ srcCopy, where_visible_region);
SetGWorld(old_port,old_gdevice);
UnlockPixels(pixmap);
}